package com.uduemc.biso.node.module.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.uduemc.biso.node.core.entities.SCategories;
import com.uduemc.biso.node.module.mapper.SCategoriesMapper;
import com.uduemc.biso.node.module.service.SCategoriesQuoteService;
import com.uduemc.biso.node.module.service.SCategoriesService;
import com.uduemc.biso.node.module.service.SSeoCategoryService;

import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;

@Service
public class SCategoriesServiceImpl implements SCategoriesService {

	private final Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	private SCategoriesMapper sCategoriesMapper;

	@Autowired
	private SCategoriesQuoteService sCategoriesQuoteServiceImpl;

	@Autowired
	private SSeoCategoryService sSeoCategoryServiceImpl;

	@Override
	public SCategories insertAndUpdateCreateAt(SCategories sCategories) {
		sCategoriesMapper.insert(sCategories);
		SCategories findOne = findOne(sCategories.getId());
		Date createAt = sCategories.getCreateAt();
		if (createAt != null) {
			sCategoriesMapper.updateCreateAt(findOne.getId(), createAt, SCategories.class);
		}
		return findOne;
	}

	@Override
	public SCategories insert(SCategories sCategories) {
		sCategoriesMapper.insert(sCategories);
		return findOne(sCategories.getId());
	}

	@Override
	public SCategories insertSelective(SCategories sCategories) {
		sCategoriesMapper.insertSelective(sCategories);
		return findOne(sCategories.getId());
	}

	@Override
	public SCategories updateById(SCategories sCategories) {
		sCategoriesMapper.updateByPrimaryKey(sCategories);
		return findOne(sCategories.getId());
	}

	@Override
	public SCategories updateByIdSelective(SCategories sCategories) {
		sCategoriesMapper.updateByPrimaryKeySelective(sCategories);
		return findOne(sCategories.getId());
	}

	@Override
	public SCategories findOne(Long id) {
		return sCategoriesMapper.selectByPrimaryKey(id);
	}

	@Override
	public List<SCategories> findAll(Pageable pageable) {
		int pageNumber = pageable.getPageNumber();
		int pageSize = pageable.getPageSize();
		PageHelper.startPage(pageNumber, pageSize);
		return sCategoriesMapper.selectAll();
	}

	@Override
	public List<SCategories> findAllByHostSiteId(long hostId, long siteId) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		return sCategoriesMapper.selectByExample(example);
	}

	@Override
	public void deleteById(Long id) {
		sCategoriesMapper.deleteByPrimaryKey(id);
	}

	@Override
	public int deleteByHostSiteId(long hostId, long siteId) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		return sCategoriesMapper.deleteByExample(example);
	}

	@Override
	public int totalByHostId(Long hostId) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		return sCategoriesMapper.selectCountByExample(example);
	}

	@Override
	public int totalBySiteId(Long siteId) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("siteId", siteId);
		return sCategoriesMapper.selectCountByExample(example);
	}

	@Override
	public int totalBySystemId(Long systemId) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("systemId", systemId);
		return sCategoriesMapper.selectCountByExample(example);
	}

	@Override
	public int totalByHostSiteId(Long hostId, Long siteId) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		return sCategoriesMapper.selectCountByExample(example);
	}

	@Override
	public int totalByHostSiteSystemId(Long hostId, Long siteId, Long systemId) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		criteria.andEqualTo("systemId", systemId);
		return sCategoriesMapper.selectCountByExample(example);
	}

	@Override
	public List<SCategories> findInfosBySystemId(Long systemId) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("systemId", systemId);
		return sCategoriesMapper.selectByExample(example);
	}

	@Override
	public boolean deleteBySCategories(SCategories sCategories) {
		List<SCategories> list = new ArrayList<>();
		list.add(sCategories);
		return deleteBySCategories(list);
	}

	/**
	 * 删除步骤 要删除 sCategories 的同时也要删除其引用的数据表和SEO信息
	 */
	@Override
	@Transactional
	public boolean deleteBySCategories(List<SCategories> list) {
		for (SCategories sCategories : list) {
			// 通过分类ID，删除该分类的引用
			if (!sCategoriesQuoteServiceImpl.deleteByCategoryId(sCategories.getId())) {
				String message = "通过sCategories删除分类引用数据失败！sCategories.getId(): " + sCategories.getId();
				logger.error(message);
				throw new RuntimeException(message);
			}
			// 删除该分类的SEO信息数据
			if (!sSeoCategoryServiceImpl.deleteByCategoryId(sCategories.getId())) {
				String message = "通过sCategories删除分类的SEO数据失败！sCategories.getId(): " + sCategories.getId();
				logger.error(message);
				throw new RuntimeException(message);
			}

			// 再删除本分类
			int delete = sCategoriesMapper.delete(sCategories);
			if (delete < 1) {
				String message = "通过sCategories删除本分类数据失败！sCategories: " + sCategories.toString();
				logger.error(message);
				throw new RuntimeException(message);
			}
		}
		return true;
	}

	@Override
	@Transactional
	public boolean deleteBySystemId(Long systemId) {
		// 首先删除该系统分类的引用
		if (!sCategoriesQuoteServiceImpl.deleteBySystemId(systemId)) {
			String message = "通过systemId删除分类引用数据失败！systemId: " + systemId;
			logger.error(message);
			throw new RuntimeException(message);
		}
		// 删除 SEO
		if (!sSeoCategoryServiceImpl.deleteBySystemId(systemId)) {
			String message = "通过systemId删除分类的SEO数据失败！systemId: " + systemId;
			logger.error(message);
			throw new RuntimeException(message);
		}
		// 删除该系统的分类
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("systemId", systemId);
		int selectCountByExample = sCategoriesMapper.selectCountByExample(example);
		if (selectCountByExample < 1) {
			return true;
		}
		return sCategoriesMapper.deleteByExample(example) > 0;
	}

	@Override
	public List<SCategories> findByHostSiteSystemId(Long hostId, Long siteId, Long systemId) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		criteria.andEqualTo("systemId", systemId);
		return sCategoriesMapper.selectByExample(example);
	}

	@Override
	public SCategories findByHostSiteSystemIdAndId(Long hostId, Long siteId, Long systemId, Long Id) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("id", Id);
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		criteria.andEqualTo("systemId", systemId);
		return sCategoriesMapper.selectOneByExample(example);
	}

	@Override
	public SCategories findByIdHostSiteId(Long id, Long hostId, Long siteId) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("id", id);
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		List<SCategories> selectByExample = sCategoriesMapper.selectByExample(example);
		if (CollectionUtils.isEmpty(selectByExample)) {
			return null;
		}
		return selectByExample.get(0);
	}

	@Override
	public List<SCategories> findByHostSiteSystemIdPageSizeOrderBy(Long hostId, Long siteId, Long systemId, int pageSize, String orderBy) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		criteria.andEqualTo("systemId", systemId);
		example.setOrderByClause(orderBy);
		if (pageSize > 0) {
			PageHelper.startPage(0, pageSize);
		}
		return sCategoriesMapper.selectByExample(example);
	}

	@Override
	public List<SCategories> findByHostSiteSystemIdPageSizeOrderBy(Long hostId, Long siteId, Long systemId, String orderBy) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		criteria.andEqualTo("systemId", systemId);
		example.setOrderByClause(orderBy);
		return sCategoriesMapper.selectByExample(example);
	}

	@Override
	public SCategories insertAppendOrderNum(SCategories sCategories) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", sCategories.getHostId());
		criteria.andEqualTo("siteId", sCategories.getSiteId());
		criteria.andEqualTo("systemId", sCategories.getSystemId());
		criteria.andEqualTo("parentId", sCategories.getParentId());
		example.setOrderByClause("`order_num` DESC");
		PageHelper.startPage(0, 1);
		List<SCategories> selectByExample = sCategoriesMapper.selectByExample(example);
		if (CollectionUtils.isEmpty(selectByExample)) {
			sCategories.setOrderNum(1);
		} else {
			sCategories.setOrderNum(selectByExample.get(0).getOrderNum() + 1);
		}
		return insert(sCategories);
	}

	@Override
	public List<SCategories> findByParentId(Long id) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("parentId", id);
		return sCategoriesMapper.selectByExample(example);
	}

	@Override
	public List<SCategories> findByAncestors(Long id) {
		List<SCategories> result = findInfosByParentIdRecursion(findByParentId(id));
		result.add(findOne(id));
		logger.info("findByAncestors: " + result);
		return result;
	}

	public List<SCategories> findInfosByParentIdRecursion(List<SCategories> list) {
		List<SCategories> result = new ArrayList<>();
		for (SCategories sCategories : list) {
			List<SCategories> infosByParentId = findByParentId(sCategories.getId());
			if (!CollectionUtils.isEmpty(infosByParentId)) {
				List<SCategories> infos = findInfosByParentIdRecursion(infosByParentId);
				result.addAll(infos);
			}
		}
		list.addAll(result);
		list = new ArrayList<>(new LinkedHashSet<>(list));
		return list;
	}

	@Override
	@Transactional
	public boolean deleteByList(List<SCategories> list) {
		if (CollectionUtils.isEmpty(list)) {
			return true;
		}
		return deleteBySCategories(list);
	}

	@Override
	public boolean existByHostSiteListCagetoryIds(long hostId, long siteId, List<Long> categoryIds) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		criteria.andIn("id", categoryIds);
		int total = sCategoriesMapper.selectCountByExample(example);
		return total == categoryIds.size();
	}

	@Override
	public boolean existByHostSiteSystemCagetoryIds(long hostId, long siteId, long systemId, List<Long> categoryIds) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		criteria.andEqualTo("systemId", systemId);
		criteria.andIn("id", categoryIds);
		int total = sCategoriesMapper.selectCountByExample(example);
		return total == categoryIds.size();
	}

	@Override
	public SCategories findByHostSiteIdAndId(long hostId, long siteId, long id) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("id", id);
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		List<SCategories> selectByExample = sCategoriesMapper.selectByExample(example);
		if (CollectionUtils.isEmpty(selectByExample)) {
			return null;
		}
		return selectByExample.get(0);
	}

	@Override
	public PageInfo<SCategories> findPageInfoAll(long hostId, long siteId, int pageNum, int pageSize) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		PageHelper.startPage(pageNum, pageSize);
		List<SCategories> listSCategories = sCategoriesMapper.selectByExample(example);
		PageInfo<SCategories> result = new PageInfo<>(listSCategories);
		return result;
	}

	@Override
	public PageInfo<SCategories> findPageInfoAll(long hostId, long siteId, long systemId, int pageNum, int pageSize) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		criteria.andEqualTo("systemId", systemId);
		PageHelper.startPage(pageNum, pageSize);
		List<SCategories> listSCategories = sCategoriesMapper.selectByExample(example);
		PageInfo<SCategories> result = new PageInfo<>(listSCategories);
		return result;
	}

	@Override
	public SCategories findByHostSiteIdAndRewrite(long hostId, long siteId, String rewrite) {
		Example example = new Example(SCategories.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("hostId", hostId);
		criteria.andEqualTo("siteId", siteId);
		criteria.andEqualTo("rewrite", rewrite);
		SCategories selectOneByExample = sCategoriesMapper.selectOneByExample(example);
		return selectOneByExample;
	}

}
